<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.2.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/vhuichen.ico">
  <link rel="icon" type="image/png" sizes="32x32" href="/vhuichen.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/vhuichen.ico">
  <link rel="mask-icon" href="/vhuichen.ico" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" integrity="sha256-AbA177XfpSnFEvgpYu1jMygiLabzPCJCRIBtR5jGc0k=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"vhuichen.github.io","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.13.0","exturl":false,"sidebar":{"position":"left","display":"display","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"Searching...","empty":"We didn't find any results for the search: ${query}","hits_time":"${hits} results found in ${time} ms","hits":"${hits} results found"}}</script><script src="/js/config.js"></script>

    <meta name="description" content="第六章：块与大中枢派发(1)第37条：理解“块”这一概念块与函数类似，只不过是直接定义在另一个函数里，和定义他的那个函数共享一个范围内的东西。块类型的语法结构如下： 1return_type (^block_name)(parameters)  变量捕获block 可以捕获外部变量，例如：   12345int additional &#x3D; 5;int (^addBlock)(int a, int b">
<meta property="og:type" content="article">
<meta property="og:title" content="《Effective Objective-C 2.0》第六章阅读笔记(1)">
<meta property="og:url" content="https://vhuichen.github.io/2018/05/2018/05/%E3%80%8AEffective%20Objective-C%202.0%E3%80%8B%E7%AC%AC%E5%85%AD%E7%AB%A0%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0(1)/index.html">
<meta property="og:site_name" content="vhuichen">
<meta property="og:description" content="第六章：块与大中枢派发(1)第37条：理解“块”这一概念块与函数类似，只不过是直接定义在另一个函数里，和定义他的那个函数共享一个范围内的东西。块类型的语法结构如下： 1return_type (^block_name)(parameters)  变量捕获block 可以捕获外部变量，例如：   12345int additional &#x3D; 5;int (^addBlock)(int a, int b">
<meta property="og:locale">
<meta property="og:image" content="http://ovsbvt5li.bkt.clouddn.com/18-5-18/27886440.jpg">
<meta property="article:published_time" content="2018-05-14T16:00:00.000Z">
<meta property="article:modified_time" content="2018-07-01T08:19:43.082Z">
<meta property="article:author" content="vhuichen">
<meta property="article:tag" content="Effective Objective-C 2.0">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://ovsbvt5li.bkt.clouddn.com/18-5-18/27886440.jpg">


<link rel="canonical" href="https://vhuichen.github.io/2018/05/2018/05/%E3%80%8AEffective%20Objective-C%202.0%E3%80%8B%E7%AC%AC%E5%85%AD%E7%AB%A0%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0(1)/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-Hans","comments":true,"permalink":"https://vhuichen.github.io/2018/05/2018/05/%E3%80%8AEffective%20Objective-C%202.0%E3%80%8B%E7%AC%AC%E5%85%AD%E7%AB%A0%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0(1)/","path":"2018/05/2018/05/《Effective Objective-C 2.0》第六章阅读笔记(1)/","title":"《Effective Objective-C 2.0》第六章阅读笔记(1)"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>《Effective Objective-C 2.0》第六章阅读笔记(1) | vhuichen</title>
  






  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">vhuichen</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">记录、分享</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section">Home</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section">Archives</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section">About</a></li>
  </ul>
</nav>




</div>
        
  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%AC%AC%E5%85%AD%E7%AB%A0%EF%BC%9A%E5%9D%97%E4%B8%8E%E5%A4%A7%E4%B8%AD%E6%9E%A2%E6%B4%BE%E5%8F%91-1"><span class="nav-number">1.</span> <span class="nav-text">第六章：块与大中枢派发(1)</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC37%E6%9D%A1%EF%BC%9A%E7%90%86%E8%A7%A3%E2%80%9C%E5%9D%97%E2%80%9D%E8%BF%99%E4%B8%80%E6%A6%82%E5%BF%B5"><span class="nav-number">1.1.</span> <span class="nav-text">第37条：理解“块”这一概念</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%8F%98%E9%87%8F%E6%8D%95%E8%8E%B7"><span class="nav-number">1.1.0.1.</span> <span class="nav-text">变量捕获</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#block-%E5%85%B3%E9%94%AE%E5%AD%97%E4%BF%AE%E9%A5%B0%E5%8F%98%E9%87%8F"><span class="nav-number">1.1.0.2.</span> <span class="nav-text">__block 关键字修饰变量</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%BC%95%E7%94%A8%E5%BE%AA%E7%8E%AF"><span class="nav-number">1.1.0.3.</span> <span class="nav-text">引用循环</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%9D%97%E7%9A%84%E5%86%85%E9%83%A8%E7%BB%93%E6%9E%84"><span class="nav-number">1.1.0.4.</span> <span class="nav-text">块的内部结构</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%85%A8%E5%B1%80%E5%9D%97%E3%80%81%E6%A0%88%E5%9D%97%E5%8F%8A%E5%A0%86%E5%9D%97"><span class="nav-number">1.1.0.5.</span> <span class="nav-text">全局块、栈块及堆块</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%85%A8%E5%B1%80%E5%9D%97"><span class="nav-number">1.1.0.6.</span> <span class="nav-text">全局块</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%A6%81%E7%82%B9"><span class="nav-number">1.1.1.</span> <span class="nav-text">要点</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC38%E6%9D%A1%EF%BC%9A%E4%B8%BA%E5%B8%B8%E7%94%A8%E7%9A%84%E5%9D%97%E7%B1%BB%E5%9E%8B%E5%88%9B%E5%BB%BAtypedef"><span class="nav-number">1.2.</span> <span class="nav-text">第38条：为常用的块类型创建typedef</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E4%B8%8D%E6%98%93%E8%AF%BB"><span class="nav-number">1.2.0.1.</span> <span class="nav-text">不易读</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E4%B8%8D%E6%98%93%E4%BF%AE%E6%94%B9"><span class="nav-number">1.2.0.2.</span> <span class="nav-text">不易修改</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%80%BB%E7%BB%93"><span class="nav-number">1.2.1.</span> <span class="nav-text">总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC39%E6%9D%A1%EF%BC%9A%E7%94%A8-handler-%E5%9D%97%E9%99%8D%E4%BD%8E%E4%BB%A3%E7%A0%81%E5%88%86%E6%95%A3%E7%A8%8B%E5%BA%A6"><span class="nav-number">1.3.</span> <span class="nav-text">第39条：用 handler 块降低代码分散程度</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#delegate"><span class="nav-number">1.3.1.</span> <span class="nav-text">delegate</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#block"><span class="nav-number">1.3.2.</span> <span class="nav-text">block</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%80%BB%E7%BB%93-1"><span class="nav-number">1.3.3.</span> <span class="nav-text">总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC40%E6%9D%A1%EF%BC%9A%E7%94%A8-block-%E5%BC%95%E7%94%A8%E5%85%B6%E6%89%80%E5%B1%9E%E5%AF%B9%E8%B1%A1%E6%97%B6%E4%B8%8D%E8%A6%81%E5%87%BA%E7%8E%B0%E5%BC%95%E7%94%A8%E5%BE%AA%E7%8E%AF"><span class="nav-number">1.4.</span> <span class="nav-text">第40条：用 block 引用其所属对象时不要出现引用循环</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%80%BB%E7%BB%93-2"><span class="nav-number">1.4.1.</span> <span class="nav-text">总结</span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="vhuichen"
      src="/images/vhuichen.jpg">
  <p class="site-author-name" itemprop="name">vhuichen</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">78</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">11</span>
        <span class="site-state-item-name">categories</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">86</span>
        <span class="site-state-item-name">tags</span></a>
      </div>
  </nav>
</div>



        </div>
      </div>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top" role="button" aria-label="Back to top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-Hans">
    <link itemprop="mainEntityOfPage" href="https://vhuichen.github.io/2018/05/2018/05/%E3%80%8AEffective%20Objective-C%202.0%E3%80%8B%E7%AC%AC%E5%85%AD%E7%AB%A0%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0(1)/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/vhuichen.jpg">
      <meta itemprop="name" content="vhuichen">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="vhuichen">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="《Effective Objective-C 2.0》第六章阅读笔记(1) | vhuichen">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          《Effective Objective-C 2.0》第六章阅读笔记(1)
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">Posted on</span>

      <time title="Created: 2018-05-15 00:00:00" itemprop="dateCreated datePublished" datetime="2018-05-15T00:00:00+08:00">2018-05-15</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">Edited on</span>
      <time title="Modified: 2018-07-01 16:19:43" itemprop="dateModified" datetime="2018-07-01T16:19:43+08:00">2018-07-01</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">In</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/iOS%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">iOS开发</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h1 id="第六章：块与大中枢派发-1"><a href="#第六章：块与大中枢派发-1" class="headerlink" title="第六章：块与大中枢派发(1)"></a><center>第六章：块与大中枢派发(1)</center></h1><h2 id="第37条：理解“块”这一概念"><a href="#第37条：理解“块”这一概念" class="headerlink" title="第37条：理解“块”这一概念"></a>第37条：理解“块”这一概念</h2><p>块与函数类似，只不过是直接定义在另一个函数里，和定义他的那个函数共享一个范围内的东西。<br>块类型的语法结构如下：</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">return_type (^block_name)(parameters)</span><br></pre></td></tr></table></figure>

<h4 id="变量捕获"><a href="#变量捕获" class="headerlink" title="变量捕获"></a>变量捕获</h4><p>block 可以捕获外部变量，例如：  </p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> additional = <span class="number">5</span>;</span><br><span class="line"><span class="type">int</span> (^addBlock)(<span class="type">int</span> a, <span class="type">int</span> b) = ^(<span class="type">int</span> a, <span class="type">int</span> b) &#123;</span><br><span class="line">    <span class="keyword">return</span> a + b + additional;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">int</span> add = addBlock(<span class="number">2</span>, <span class="number">5</span>);</span><br></pre></td></tr></table></figure>
<p>block 捕获 additional 变量，仅仅是捕获 additional 那一刻的值，捕获了之后，如果外部 additional 的值改变了，此时并不会影响 block 内部 additional 的值，因为这个值是一个常量，分别存放在两个不同的内存中，是互不干扰的。如果尝试去修改此时 block 内部的additional 变量的值，编译器会报错。<br>事实上，在 ARC 环境下，block 外部的 additional 变量是存放在栈中的，而 block 内部的 additional 变量则是存放在堆中的。<br>那么，如果需要 block 内外共享一份内存呢？这时可以给变量加上 <strong>__block</strong> 关键字。  </p>
<h4 id="block-关键字修饰变量"><a href="#block-关键字修饰变量" class="headerlink" title="__block 关键字修饰变量"></a>__block 关键字修饰变量</h4><p>下面用 __block 关键字修饰 additional 变量，那么当外部的 additional 变量改变时，里面的 additional 值也会改变。因为这两个是同一个值。</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">__block <span class="type">int</span> additional = <span class="number">5</span>;</span><br><span class="line"><span class="type">int</span> (^addBlock)(<span class="type">int</span> a, <span class="type">int</span> b) = ^(<span class="type">int</span> a, <span class="type">int</span> b) &#123;</span><br><span class="line">    additional = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">return</span> a + b + additional;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">int</span> add = addBlock(<span class="number">2</span>, <span class="number">5</span>);</span><br></pre></td></tr></table></figure>
<p>用 __block 修饰的变量存放在堆中，和 block 中的 additional 共享同一份内存，是同一个数据。</p>
<h4 id="引用循环"><a href="#引用循环" class="headerlink" title="引用循环"></a>引用循环</h4><p>如果在 block 中引用了某个对象，比如self，而这个对象正好直接或者间接引用了 block ，那么就会造成引用循环。<br>所以一般在 block 中引用的变量都会使用弱引用。</p>
<h4 id="块的内部结构"><a href="#块的内部结构" class="headerlink" title="块的内部结构"></a>块的内部结构</h4><p>块本身也是对象，在存放块对象的内存区域中，首个变量是指向Class对象的指针，该指针叫做isa。其余内存里含有块对象正常运转所需的各种信息。下图描述了块对象的内存布局。<br><img src="http://ovsbvt5li.bkt.clouddn.com/18-5-18/27886440.jpg">  </p>
<p>在内存布局中，最重要的就是invoke变量，这是个函数指针，指向块的实现代码。函数原型至少要接受一个void *型的参数，此参数代表块。</p>
<p>descriptor 变量是指向结构体的指针，每个块里都包含此结构体，其中声明了块对象的总体大小，还声明了 copy 与 dispose 这两个辅助函数所对应的函数指针。辅助函数在拷贝及丢弃块对象时运行，其中会执行一些操作，比方说，前者 copy 要保留捕获的对象，而后者 dispose 则将之释放。</p>
<p>block 会把它所捕获的所有变量都拷贝一份，拷贝的是指向这些对象的指针变量。invoke函数为何需要把块对象作为参数传进来呢？原因就在于，执行块时，要从内存中把这些捕获到的变量读出来。</p>
<h4 id="全局块、栈块及堆块"><a href="#全局块、栈块及堆块" class="headerlink" title="全局块、栈块及堆块"></a>全局块、栈块及堆块</h4><p>定义块时，其所占的内存区域是分配在栈中的。这就是说，块只在定义他的那个范围内有效。例如，下面这段代码会有问题：  </p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> (^block)();</span><br><span class="line"><span class="keyword">if</span> ( <span class="comment">/* ... */</span> ) &#123;</span><br><span class="line">    block = ^&#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@&quot;Block A&quot;</span>);</span><br><span class="line">    &#125;;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    block = ^&#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@&quot;Block B&quot;</span>);</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br><span class="line">block();</span><br></pre></td></tr></table></figure>
<p>上面两个 block 都是分配在栈中的，当离开了作用域后，就会将其释放掉，也就是两个 block 只在 if else 内有效。所以离开了 if slse 后在执行 block的话就可能会出问题。若编译器未覆写待执行的 block，则程序照常运行，若覆写，则程序崩溃。</p>
<p><strong>其实这就是为什么 block 属性要使用 copy 修饰的原因。</strong>给 block 发送 copy 消息将其拷贝。这样就可以把 block 从栈复制到堆了。拷贝后的 block，可以在定义它的范围之外使用。而且，一旦复制到堆上，块就成了带引用计数的对象了。后续的复制操作都不会真的执行复制，只是递增对象的引用计数。 </p>
<p>给上面的 block 发送 copy 消息就可以保证程序可以正确运行   </p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> (^block)();</span><br><span class="line"><span class="keyword">if</span> ( <span class="comment">/* ... */</span> ) &#123;</span><br><span class="line">    block = [^&#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@&quot;Block A&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">copy</span>];</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    block = [^&#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@&quot;Block B&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">copy</span>];</span><br><span class="line">&#125;</span><br><span class="line">block();</span><br></pre></td></tr></table></figure>
<p>此时的 block 是分配到堆的，这样在 if else 外也可以使用。</p>
<h4 id="全局块"><a href="#全局块" class="headerlink" title="全局块"></a>全局块</h4><p>这种块不会捕捉任何状态（比如外围的变量等），运行时也无须有状态来参与。块所使用的整个内存区域，在编译期已经完全确定了，因此，全局块可以声明在全局内存里，而不需要在每次用到的时候于栈中创建。另外，全局块的拷贝操作是个空操作，因为全局块绝不可能为系统所回收。这种块实际上相当于单例。</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> (^block)() = ^&#123;</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@&quot;This is a block&quot;</span>);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>此 block 所需的全部信息都能在编译期确定，所以可把它做成全局块。</p>
<h3 id="要点"><a href="#要点" class="headerlink" title="要点"></a>要点</h3><p>块可以分配在栈、堆或者全局上。分配在栈上的块可以拷贝到堆里，就和标准的 Objective-C 对象一样具备了引用计数。</p>
<h2 id="第38条：为常用的块类型创建typedef"><a href="#第38条：为常用的块类型创建typedef" class="headerlink" title="第38条：为常用的块类型创建typedef"></a>第38条：为常用的块类型创建typedef</h2><p>一开始我们定义 block 是这样的</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> (^variableName)(<span class="type">BOOL</span> flag, <span class="type">int</span> value) = ^(<span class="type">BOOL</span> flag, <span class="type">int</span> value) &#123;</span><br><span class="line">    <span class="keyword">return</span> someInt;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>这样做会有两个不友好的问题 </p>
<h4 id="不易读"><a href="#不易读" class="headerlink" title="不易读"></a>不易读</h4><p>如果我们提供的接口中有好几个 block ，每个 block 中又有好几个参数，这样会感觉比较难读。<br>解决方法是给 block 类型定义一个别名  </p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">int</span> (^EOCSomeBlock)(<span class="type">BOOL</span> flag, <span class="type">int</span> value);</span><br><span class="line"></span><br><span class="line">EOCSomeBlock block = ^(<span class="type">BOOL</span> flag, <span class="type">int</span> value) &#123;</span><br><span class="line">    <span class="keyword">return</span> someInt;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>这样使用起来就会简介很多。</p>
<h4 id="不易修改"><a href="#不易修改" class="headerlink" title="不易修改"></a>不易修改</h4><p>当打算重构 block 的类型签名时，比方说，要给原来的 completion handler block 再加一个参数，如果没有使用别名的话，那么我们需要将所有使用了该 block 的地方都修改，这样显得过于繁杂。如果使用了别名的话，那么只需修改类型定义语句即可。</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>当要在多个地方使用同种签名的 block 时，应该给该 block 定义一个别名，然后在需要的地方使用该别名定义 block 。</p>
<h2 id="第39条：用-handler-块降低代码分散程度"><a href="#第39条：用-handler-块降低代码分散程度" class="headerlink" title="第39条：用 handler 块降低代码分散程度"></a>第39条：用 handler 块降低代码分散程度</h2><p>程序在执行任务时，通常需要 “异步执行” ，这样做的好处在于：处理用户界面的显示及触摸操作所用的线程，不会因为要执行I&#x2F;O或网络通信这类耗时的任务而阻塞。某些情况下，如果应用程序在一定时间内无响应，那么就会自动终止。“系统监控器”（system watchdog）在发现某个应用程序的主线程已经阻塞了一段时间之后，就会令其终止。  </p>
<p>通常有两种方式可以处理异步代码  </p>
<h3 id="delegate"><a href="#delegate" class="headerlink" title="delegate"></a>delegate</h3><p>使用 delegate 会使代码变得分散，当一个对象同时接收多个同种类型对象的委托时，还需要在委托方法中判断是哪个对象传来的委托。那么代码会变的更加复杂。delegate 一般用在一个委托对象有多个委托事件的情况下，比如：UITableView，其他情况可以使用 block 来实现。</p>
<h3 id="block"><a href="#block" class="headerlink" title="block"></a>block</h3><p>用 block 处理起来代码会变的更加清晰。block 可以令这种API变得更紧凑，同时也令开发者调用起来更加方便。</p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="type">void</span>)vch_successWithComplete:(VCHAddNewDeviceComplete)complete failure:(VCHFailure)failure &#123;</span><br><span class="line">    [<span class="keyword">self</span> vch_startWithComplete:^(<span class="type">id</span> object) &#123;</span><br><span class="line">        <span class="comment">// do something</span></span><br><span class="line">        complete();</span><br><span class="line">    &#125; failure:^(<span class="built_in">NSString</span> *error) &#123;</span><br><span class="line">        <span class="comment">// do something</span></span><br><span class="line">        failure(error);</span><br><span class="line">    &#125;];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里我的处理方式是将成功和失败分开处理，也可以用一个 block 来处理两个两种情况，两种方法均有优劣。具体可多看看官方的做法。</p>
<h3 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h3><p>在创建对象时，可以使用内联的handler块将相关业务逻辑一并声明。使代码变得更加紧凑。  </p>
<h2 id="第40条：用-block-引用其所属对象时不要出现引用循环"><a href="#第40条：用-block-引用其所属对象时不要出现引用循环" class="headerlink" title="第40条：用 block 引用其所属对象时不要出现引用循环"></a>第40条：用 block 引用其所属对象时不要出现引用循环</h2><p>书中的例子比较长，我用项目中的一部分代码来替代，意思是一样的   </p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">self</span>.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^&#123;</span><br><span class="line">	[<span class="keyword">self</span> queryFence];</span><br><span class="line">&#125;];</span><br><span class="line">[<span class="keyword">self</span>.tableView.mj_header beginRefreshing];</span><br></pre></td></tr></table></figure>
<p>上面的代码会出现引用循环，self -&gt; mj_header -&gt; block -&gt; self 。这个是初学时很容易犯的错误。这种情况下有两种比较常用的方法可以解决这个问题，一种就是用完 block 后，立即将其释放，另一种就是使用 __weak 关键字修饰某一环节。这里我使用第二种方法，代码如下  </p>
<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">__<span class="keyword">weak</span> <span class="keyword">typeof</span>(<span class="keyword">self</span>) weakSelf = <span class="keyword">self</span>;</span><br><span class="line"><span class="keyword">self</span>.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^&#123;</span><br><span class="line">	[weakSelf queryFence];</span><br><span class="line">&#125;];</span><br><span class="line">[<span class="keyword">self</span>.tableView.mj_header beginRefreshing];</span><br></pre></td></tr></table></figure>
<p>此时 block 弱引用了 self ，这个循环也就被打破了。</p>
<h3 id="总结-2"><a href="#总结-2" class="headerlink" title="总结"></a>总结</h3><p>如果 block 所捕获的对象直接或间接的保留了 block 本身，那么就需要解除引用循环。</p>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/Effective-Objective-C-2-0/" rel="tag"># Effective Objective-C 2.0</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/2018/05/2018/05/iOS%E5%BC%80%E5%8F%91%E4%B9%8B%E7%AC%AC%E4%B8%89%E6%96%B9%E7%99%BB%E5%BD%95%EF%BC%88%E5%BE%AE%E4%BF%A1%E3%80%81QQ%EF%BC%89/" rel="prev" title="iOS开发之第三方登录（微信、QQ）">
                  <i class="fa fa-chevron-left"></i> iOS开发之第三方登录（微信、QQ）
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/2018/05/2018/05/iOS%E5%9F%BA%E7%A1%80%E4%B9%8B%E4%B8%80%E4%B8%AAWorkspace%E4%B8%8B%E6%9C%89%E5%A4%9A%E4%B8%AAProject/" rel="next" title="iOS基础之一个Workspace下有多个Project">
                  iOS基础之一个Workspace下有多个Project <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 2015 – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">vhuichen</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/pisces/" rel="noopener" target="_blank">NexT.Pisces</a>
  </div>

    </div>
  </footer>

  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script>

  





  





</body>
</html>
